import 'dart:io';
import 'package:dio/dio.dart';
import '../../data/models/upload/upload_task.dart';
import '../../core/constants/api_constants.dart';
import '../../utils/logger.dart';
import '../../core/exceptions/app_exception.dart';

/// 上传服务类
class UploadService {
  final Dio _dio;
  final _logger = Logger('UploadService');
  static const int _chunkSize = 5 * 1024 * 1024; // 5MB
  static const int _smallFileThreshold = 20 * 1024 * 1024; // 20MB

  UploadService(this._dio);

  /// 上传文件
  Future<void> uploadFile(
    UploadTask task, {
    required void Function(double) onProgress,
  }) async {
    try {
      if (task.fileSize > _smallFileThreshold) {
        await _uploadChunkFile(task, onProgress: onProgress);
      } else {
        await _uploadSmallFile(task, onProgress: onProgress);
      }
    } catch (e) {
      _logger.error('上传文件失败: ${e.toString()}');
      if (e is DioException) {
        throw NetworkException(
          '网络请求失败: ${e.message}',
          code: e.response?.statusCode,
          data: e.response?.data,
        );
      }
      rethrow;
    }
  }

  /// 上传小文件
  Future<void> _uploadSmallFile(
    UploadTask task, {
    required void Function(double) onProgress,
  }) async {
    final file = File(task.filePath);
    if (!await file.exists()) {
      throw ValidationException('文件不存在: ${task.filePath}');
    }

    final formData = FormData.fromMap({
      'file': await MultipartFile.fromFile(
        task.filePath,
        filename: task.fileName,
      ),
      'directory_id': task.directoryId,
    });

    await _dio.post(
      FilesApiConstants.upload,
      data: formData,
      onSendProgress: (count, total) {
        onProgress(count / total);
      },
    );
  }

  /// 分片上传大文件
  Future<void> _uploadChunkFile(
    UploadTask task, {
    required void Function(double) onProgress,
  }) async {
    final file = File(task.filePath);
    if (!await file.exists()) {
      throw ValidationException('文件不存在: ${task.filePath}');
    }

    // 1. 初始化分片上传
    final initResponse = await _dio.post(
      ChunkUploadApiConstants.init,
      data: {
        'file_name': task.fileName,
        'file_size': task.fileSize,
        'chunk_size': _chunkSize,
        'mime_type': 'application/octet-stream',
        'directory_id': task.directoryId,
      },
    );

    final taskId = initResponse.data['data']['task_id'];
    final uploadId = initResponse.data['data']['upload_id'];
    final totalChunks = initResponse.data['data']['total_chunks'];

    // 2. 上传分片
    for (var i = 0; i < totalChunks; i++) {
      final start = i * _chunkSize;
      final end =
          (i + 1) * _chunkSize > task.fileSize
              ? task.fileSize
              : (i + 1) * _chunkSize;

      final chunk = await file.openRead(start, end).toList();
      final chunkData = chunk.expand((x) => x).toList();

      await _dio.post(
        '${ChunkUploadApiConstants.uploadChunk}?task_id=$taskId&chunk_number=${i + 1}',
        data: FormData.fromMap({
          'file': MultipartFile.fromBytes(
            chunkData,
            filename: 'chunk_${i + 1}',
          ),
        }),
      );

      onProgress((i + 1) / totalChunks);
    }

    // 3. 完成上传
    await _dio.post(
      ChunkUploadApiConstants.complete,
      data: {'task_id': taskId},
    );
  }

  /// 暂停上传
  Future<void> pauseUpload(String taskId) async {
    // TODO: 实现暂停上传逻辑
    _logger.info('暂停上传任务: $taskId');
  }

  /// 取消上传
  Future<void> cancelUpload(String taskId) async {
    try {
      await _dio.post(ChunkUploadApiConstants.abort(taskId));
    } catch (e) {
      _logger.error('取消上传失败: ${e.toString()}');
      if (e is DioException) {
        throw NetworkException('取消上传请求失败: ${e.message}');
      }
    }
  }
}
